"""
调度器服务 - 管理定时任务和数据同步
"""

import asyncio
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Callable, Any
from dataclasses import dataclass, field
from enum import Enum
import json
from contextlib import asynccontextmanager

from .core.config import SystemConfig
from .core.database import DatabaseManager
from .core.cache import CacheManager
from .data_sync_service import AkshareDataSyncService
# 定义调度器相关异常
class SchedulerError(Exception):
    """调度器异常"""
    pass

class TaskExecutionError(Exception):
    """任务执行异常"""
    pass


class TaskStatus(Enum):
    """任务状态枚举"""
    PENDING = "pending"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"


class TaskPriority(Enum):
    """任务优先级枚举"""
    LOW = 1
    NORMAL = 2
    HIGH = 3
    CRITICAL = 4


@dataclass
class ScheduledTask:
    """调度任务配置"""
    task_id: str
    name: str
    func: Callable
    cron_expression: str
    priority: TaskPriority = TaskPriority.NORMAL
    max_retries: int = 3
    timeout: int = 3600  # 1小时超时
    enabled: bool = True
    last_run: Optional[datetime] = None
    next_run: Optional[datetime] = None
    status: TaskStatus = TaskStatus.PENDING
    retry_count: int = 0
    error_message: Optional[str] = None
    execution_time: Optional[float] = None
    metadata: Dict[str, Any] = field(default_factory=dict)


@dataclass
class TaskExecution:
    """任务执行记录"""
    execution_id: str
    task_id: str
    start_time: datetime
    end_time: Optional[datetime] = None
    status: TaskStatus = TaskStatus.RUNNING
    result: Optional[Any] = None
    error_message: Optional[str] = None
    execution_time: Optional[float] = None


class CronParser:
    """简单的Cron表达式解析器"""
    
    @staticmethod
    def parse_cron(cron_expression: str) -> Dict[str, Any]:
        """解析Cron表达式"""
        parts = cron_expression.strip().split()
        if len(parts) != 5:
            raise ValueError(f"无效的Cron表达式: {cron_expression}")
        
        return {
            'minute': parts[0],
            'hour': parts[1],
            'day': parts[2],
            'month': parts[3],
            'weekday': parts[4]
        }
    
    @staticmethod
    def next_run_time(cron_expression: str, from_time: Optional[datetime] = None) -> datetime:
        """计算下次运行时间（简化实现）"""
        if from_time is None:
            from_time = datetime.now()
        
        # 简化实现，支持常见的Cron表达式
        if cron_expression == "0 0 * * *":  # 每天午夜
            next_time = from_time.replace(hour=0, minute=0, second=0, microsecond=0)
            if next_time <= from_time:
                next_time += timedelta(days=1)
            return next_time
        elif cron_expression == "0 */1 * * *":  # 每小时
            next_time = from_time.replace(minute=0, second=0, microsecond=0)
            if next_time <= from_time:
                next_time += timedelta(hours=1)
            return next_time
        elif cron_expression == "*/5 * * * *":  # 每5分钟
            minute = (from_time.minute // 5 + 1) * 5
            if minute >= 60:
                next_time = from_time.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)
            else:
                next_time = from_time.replace(minute=minute, second=0, microsecond=0)
            return next_time
        elif cron_expression == "*/1 * * * *":  # 每分钟
            next_time = from_time.replace(second=0, microsecond=0) + timedelta(minutes=1)
            return next_time
        else:
            # 默认每小时执行
            next_time = from_time.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)
            return next_time


class TaskScheduler:
    """任务调度器"""
    
    def __init__(self, config: SystemConfig):
        self.config = config
        self.logger = logging.getLogger(__name__)
        self.tasks: Dict[str, ScheduledTask] = {}
        self.executions: Dict[str, TaskExecution] = {}
        self.running = False
        self.scheduler_task: Optional[asyncio.Task] = None
        self.db_manager: Optional[DatabaseManager] = None
        self.cache_manager: Optional[CacheManager] = None
        self.data_sync_service: Optional[AkshareDataSyncService] = None
        
    async def initialize(self):
        """初始化调度器"""
        try:
            # 初始化依赖服务
            # 使用全局实例
            from .core.database import db_manager
            from .core.cache import cache_manager
            from .data_sync_service import data_sync_service
            
            self.db_manager = db_manager
            self.cache_manager = cache_manager
            self.data_sync_service = data_sync_service
            
            # 确保数据同步服务已初始化
            if self.data_sync_service and not self.data_sync_service._initialized:
                await self.data_sync_service.initialize()
            
            # 注册默认任务
            await self._register_default_tasks()
            
            self.logger.info("任务调度器初始化完成")
            
        except Exception as e:
            self.logger.error(f"任务调度器初始化失败: {e}")
            raise SchedulerError(f"调度器初始化失败: {e}")
    
    async def _register_default_tasks(self):
        """注册默认任务"""
        # 股票数据同步任务
        await self.register_task(
            task_id="sync_stock_basic",
            name="同步股票基本信息",
            func=self._sync_stock_basic,
            cron_expression="0 0 * * *",  # 每天午夜
            priority=TaskPriority.HIGH
        )
        
        await self.register_task(
            task_id="sync_stock_daily",
            name="同步股票日线数据",
            func=self._sync_stock_daily,
            cron_expression="0 */1 * * *",  # 每小时
            priority=TaskPriority.HIGH
        )
        
        await self.register_task(
            task_id="sync_stock_realtime",
            name="同步股票实时数据",
            func=self._sync_stock_realtime,
            cron_expression="*/1 * * * *",  # 每分钟
            priority=TaskPriority.CRITICAL
        )
        
        # 指数数据同步任务
        await self.register_task(
            task_id="sync_index_basic",
            name="同步指数基本信息",
            func=self._sync_index_basic,
            cron_expression="0 0 * * *",  # 每天午夜
            priority=TaskPriority.NORMAL
        )
        
        await self.register_task(
            task_id="sync_index_daily",
            name="同步指数日线数据",
            func=self._sync_index_daily,
            cron_expression="0 */1 * * *",  # 每小时
            priority=TaskPriority.NORMAL
        )
        
        # 基金数据同步任务
        await self.register_task(
            task_id="sync_fund_basic",
            name="同步基金基本信息",
            func=self._sync_fund_basic,
            cron_expression="0 0 * * *",  # 每天午夜
            priority=TaskPriority.NORMAL
        )
        
        await self.register_task(
            task_id="sync_fund_nav",
            name="同步基金净值数据",
            func=self._sync_fund_nav,
            cron_expression="0 */1 * * *",  # 每小时
            priority=TaskPriority.NORMAL
        )
        
        # 债券数据同步任务
        await self.register_task(
            task_id="sync_bond_basic",
            name="同步债券基本信息",
            func=self._sync_bond_basic,
            cron_expression="0 0 * * *",  # 每天午夜
            priority=TaskPriority.LOW
        )
        
        # 系统维护任务
        await self.register_task(
            task_id="cleanup_cache",
            name="清理过期缓存",
            func=self._cleanup_cache,
            cron_expression="0 2 * * *",  # 每天凌晨2点
            priority=TaskPriority.LOW
        )
        
        await self.register_task(
            task_id="health_check",
            name="系统健康检查",
            func=self._health_check,
            cron_expression="*/5 * * * *",  # 每5分钟
            priority=TaskPriority.NORMAL
        )
    
    async def register_task(
        self,
        task_id: str,
        name: str,
        func: Callable,
        cron_expression: str,
        priority: TaskPriority = TaskPriority.NORMAL,
        max_retries: int = 3,
        timeout: int = 3600,
        enabled: bool = True,
        metadata: Optional[Dict[str, Any]] = None
    ):
        """注册任务"""
        try:
            # 验证Cron表达式
            CronParser.parse_cron(cron_expression)
            
            # 计算下次运行时间
            next_run = CronParser.next_run_time(cron_expression)
            
            task = ScheduledTask(
                task_id=task_id,
                name=name,
                func=func,
                cron_expression=cron_expression,
                priority=priority,
                max_retries=max_retries,
                timeout=timeout,
                enabled=enabled,
                next_run=next_run,
                metadata=metadata or {}
            )
            
            self.tasks[task_id] = task
            self.logger.info(f"任务已注册: {name} ({task_id}), 下次运行: {next_run}")
            
        except Exception as e:
            self.logger.error(f"注册任务失败: {e}")
            raise SchedulerError(f"注册任务失败: {e}")
    
    async def start(self):
        """启动调度器"""
        if self.running:
            self.logger.warning("调度器已在运行")
            return
        
        self.running = True
        self.scheduler_task = asyncio.create_task(self._scheduler_loop())
        self.logger.info("任务调度器已启动")
    
    async def stop(self):
        """停止调度器"""
        if not self.running:
            return
        
        self.running = False
        if self.scheduler_task:
            self.scheduler_task.cancel()
            try:
                await self.scheduler_task
            except asyncio.CancelledError:
                pass
        
        self.logger.info("任务调度器已停止")
    
    async def _scheduler_loop(self):
        """调度器主循环"""
        while self.running:
            try:
                current_time = datetime.now()
                
                # 获取需要执行的任务
                ready_tasks = [
                    task for task in self.tasks.values()
                    if (task.enabled and 
                        task.status != TaskStatus.RUNNING and
                        task.next_run and 
                        task.next_run <= current_time)
                ]
                
                # 按优先级排序
                ready_tasks.sort(key=lambda t: t.priority.value, reverse=True)
                
                # 执行任务
                for task in ready_tasks:
                    if not self.running:
                        break
                    
                    asyncio.create_task(self._execute_task(task))
                
                # 等待下次检查
                await asyncio.sleep(30)  # 每30秒检查一次
                
            except Exception as e:
                self.logger.error(f"调度器循环错误: {e}")
                await asyncio.sleep(60)  # 出错时等待更长时间
    
    async def _execute_task(self, task: ScheduledTask):
        """执行任务"""
        execution_id = f"{task.task_id}_{int(datetime.now().timestamp())}"
        execution = TaskExecution(
            execution_id=execution_id,
            task_id=task.task_id,
            start_time=datetime.now()
        )
        
        self.executions[execution_id] = execution
        task.status = TaskStatus.RUNNING
        
        try:
            self.logger.info(f"开始执行任务: {task.name} ({task.task_id})")
            
            # 执行任务（带超时）
            result = await asyncio.wait_for(
                task.func(),
                timeout=task.timeout
            )
            
            # 任务成功
            execution.end_time = datetime.now()
            execution.status = TaskStatus.COMPLETED
            execution.result = result
            execution.execution_time = (execution.end_time - execution.start_time).total_seconds()
            
            task.status = TaskStatus.COMPLETED
            task.last_run = execution.start_time
            task.next_run = CronParser.next_run_time(task.cron_expression, execution.end_time)
            task.retry_count = 0
            task.error_message = None
            task.execution_time = execution.execution_time
            
            self.logger.info(f"任务执行成功: {task.name}, 耗时: {execution.execution_time:.2f}秒")
            
        except asyncio.TimeoutError:
            # 任务超时
            execution.end_time = datetime.now()
            execution.status = TaskStatus.FAILED
            execution.error_message = f"任务超时 ({task.timeout}秒)"
            execution.execution_time = (execution.end_time - execution.start_time).total_seconds()
            
            await self._handle_task_failure(task, execution.error_message)
            
        except Exception as e:
            # 任务失败
            execution.end_time = datetime.now()
            execution.status = TaskStatus.FAILED
            execution.error_message = str(e)
            execution.execution_time = (execution.end_time - execution.start_time).total_seconds()
            
            await self._handle_task_failure(task, str(e))
    
    async def _handle_task_failure(self, task: ScheduledTask, error_message: str):
        """处理任务失败"""
        task.retry_count += 1
        task.error_message = error_message
        
        if task.retry_count <= task.max_retries:
            # 重试任务
            task.status = TaskStatus.PENDING
            task.next_run = datetime.now() + timedelta(minutes=5 * task.retry_count)  # 递增延迟
            self.logger.warning(f"任务失败，将重试: {task.name}, 重试次数: {task.retry_count}/{task.max_retries}")
        else:
            # 达到最大重试次数
            task.status = TaskStatus.FAILED
            task.next_run = CronParser.next_run_time(task.cron_expression)
            self.logger.error(f"任务失败，已达最大重试次数: {task.name}, 错误: {error_message}")
    
    # 数据同步任务实现
    async def _sync_stock_basic(self):
        """同步股票基本信息"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("stock_info")
        if task:
            await self.data_sync_service._execute_sync_task("stock_info", task)
        return {"status": "completed", "task": "stock_basic"}
    
    async def _sync_stock_daily(self):
        """同步股票日线数据"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("stock_daily")
        if task:
            await self.data_sync_service._execute_sync_task("stock_daily", task)
        return {"status": "completed", "task": "stock_daily"}
    
    async def _sync_stock_realtime(self):
        """同步股票实时数据"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("stock_realtime")
        if task:
            await self.data_sync_service._execute_sync_task("stock_realtime", task)
        return {"status": "completed", "task": "stock_realtime"}
    
    async def _sync_index_basic(self):
        """同步指数基本信息"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("index_realtime")
        if task:
            await self.data_sync_service._execute_sync_task("index_realtime", task)
        return {"status": "completed", "task": "index_basic"}
    
    async def _sync_index_daily(self):
        """同步指数日线数据"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("index_realtime")
        if task:
            await self.data_sync_service._execute_sync_task("index_realtime", task)
        return {"status": "completed", "task": "index_daily"}
    
    async def _sync_fund_basic(self):
        """同步基金基本信息"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("fund_realtime")
        if task:
            await self.data_sync_service._execute_sync_task("fund_realtime", task)
        return {"status": "completed", "task": "fund_basic"}
    
    async def _sync_fund_nav(self):
        """同步基金净值数据"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("fund_realtime")
        if task:
            await self.data_sync_service._execute_sync_task("fund_realtime", task)
        return {"status": "completed", "task": "fund_nav"}
    
    async def _sync_bond_basic(self):
        """同步债券基本信息"""
        if not self.data_sync_service:
            return {"status": "error", "message": "数据同步服务未初始化"}
        
        task = self.data_sync_service.sync_tasks.get("bond_realtime")
        if task:
            await self.data_sync_service._execute_sync_task("bond_realtime", task)
        return {"status": "completed", "task": "bond_basic"}
    
    # 系统维护任务实现
    async def _cleanup_cache(self):
        """清理过期缓存"""
        try:
            # 清理各类缓存
            total_cleaned = 0
            
            try:
                # 清理数据同步服务的缓存
                if self.data_sync_service:
                    await self.data_sync_service._cleanup_cache()
                    total_cleaned += 1
            except Exception as e:
                self.logger.warning(f"清理数据同步缓存失败: {e}")
            
            self.logger.info(f"缓存清理完成，清理了 {total_cleaned} 个过期项")
            return {"cleaned_items": total_cleaned}
            
        except Exception as e:
            self.logger.error(f"缓存清理失败: {e}")
            raise
    
    async def _health_check(self):
        """系统健康检查"""
        try:
            health_status = {
                "timestamp": datetime.now().isoformat(),
                "database": False,
                "cache": False,
                "data_sync": False
            }
            
            # 检查数据库连接
            try:
                from .core.database import db_manager
                async with db_manager.get_session() as session:
                    from sqlalchemy import text
                    await session.execute(text("SELECT 1"))
                health_status["database"] = True
            except Exception as e:
                self.logger.error(f"数据库健康检查失败: {e}")
            
            # 检查缓存连接
            try:
                from .core.cache import cache_manager
                cache = cache_manager.get_cache("system")
                await cache.set("health_check", "ok", ttl=60)
                result = await cache.get("health_check")
                health_status["cache"] = (result == "ok")
            except Exception as e:
                self.logger.error(f"缓存健康检查失败: {e}")
            
            # 检查数据同步服务
            try:
                if self.data_sync_service:
                    status = await self.data_sync_service.get_sync_status()
                    health_status["data_sync"] = status.get("service_status") == "running"
                else:
                    health_status["data_sync"] = False
            except Exception as e:
                self.logger.error(f"数据同步服务健康检查失败: {e}")
            
            # 记录健康状态
            all_healthy = all(health_status[key] for key in ["database", "cache", "data_sync"])
            if all_healthy:
                self.logger.debug("系统健康检查通过")
            else:
                self.logger.warning(f"系统健康检查发现问题: {health_status}")
            
            return health_status
            
        except Exception as e:
            self.logger.error(f"健康检查失败: {e}")
            raise
    
    # 管理接口
    async def get_task_status(self, task_id: Optional[str] = None) -> Dict[str, Any]:
        """获取任务状态"""
        if task_id:
            task = self.tasks.get(task_id)
            if not task:
                raise SchedulerError(f"任务不存在: {task_id}")
            
            return {
                "task_id": task.task_id,
                "name": task.name,
                "status": task.status.value,
                "enabled": task.enabled,
                "last_run": task.last_run.isoformat() if task.last_run else None,
                "next_run": task.next_run.isoformat() if task.next_run else None,
                "retry_count": task.retry_count,
                "max_retries": task.max_retries,
                "error_message": task.error_message,
                "execution_time": task.execution_time,
                "priority": task.priority.value,
                "cron_expression": task.cron_expression
            }
        else:
            return {
                "scheduler_running": self.running,
                "total_tasks": len(self.tasks),
                "enabled_tasks": len([t for t in self.tasks.values() if t.enabled]),
                "running_tasks": len([t for t in self.tasks.values() if t.status == TaskStatus.RUNNING]),
                "failed_tasks": len([t for t in self.tasks.values() if t.status == TaskStatus.FAILED]),
                "tasks": [
                    {
                        "task_id": task.task_id,
                        "name": task.name,
                        "status": task.status.value,
                        "enabled": task.enabled,
                        "next_run": task.next_run.isoformat() if task.next_run else None
                    }
                    for task in self.tasks.values()
                ]
            }
    
    async def enable_task(self, task_id: str):
        """启用任务"""
        task = self.tasks.get(task_id)
        if not task:
            raise SchedulerError(f"任务不存在: {task_id}")
        
        task.enabled = True
        if not task.next_run:
            task.next_run = CronParser.next_run_time(task.cron_expression)
        
        self.logger.info(f"任务已启用: {task.name}")
    
    async def disable_task(self, task_id: str):
        """禁用任务"""
        task = self.tasks.get(task_id)
        if not task:
            raise SchedulerError(f"任务不存在: {task_id}")
        
        task.enabled = False
        self.logger.info(f"任务已禁用: {task.name}")
    
    async def trigger_task(self, task_id: str):
        """手动触发任务"""
        task = self.tasks.get(task_id)
        if not task:
            raise SchedulerError(f"任务不存在: {task_id}")
        
        if task.status == TaskStatus.RUNNING:
            raise SchedulerError(f"任务正在运行: {task_id}")
        
        # 立即执行任务
        asyncio.create_task(self._execute_task(task))
        self.logger.info(f"任务已手动触发: {task.name}")
    
    async def get_execution_history(self, task_id: Optional[str] = None, limit: int = 100) -> List[Dict[str, Any]]:
        """获取执行历史"""
        executions = list(self.executions.values())
        
        if task_id:
            executions = [e for e in executions if e.task_id == task_id]
        
        # 按开始时间倒序排列
        executions.sort(key=lambda e: e.start_time, reverse=True)
        executions = executions[:limit]
        
        return [
            {
                "execution_id": e.execution_id,
                "task_id": e.task_id,
                "start_time": e.start_time.isoformat(),
                "end_time": e.end_time.isoformat() if e.end_time else None,
                "status": e.status.value,
                "execution_time": e.execution_time,
                "error_message": e.error_message
            }
            for e in executions
        ]
    
    @asynccontextmanager
    async def lifespan(self):
        """生命周期管理"""
        try:
            await self.initialize()
            await self.start()
            yield self
        finally:
            await self.stop()
            if self.cache_manager:
                await self.cache_manager.close()
            if self.db_manager:
                await self.db_manager.close()


# 全局调度器实例
scheduler_service: Optional[TaskScheduler] = None


async def get_scheduler_service() -> TaskScheduler:
    """获取调度器服务实例"""
    global scheduler_service
    if scheduler_service is None:
        from .core.config import SystemConfig
        config = SystemConfig()
        scheduler_service = TaskScheduler(config)
    return scheduler_service


async def initialize_scheduler(config: SystemConfig) -> TaskScheduler:
    """初始化调度器服务"""
    global scheduler_service
    scheduler_service = TaskScheduler(config)
    await scheduler_service.initialize()
    return scheduler_service